package org.iabako.client.ui.form.business;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import org.iabako.client.tools.DefaultSuggestHandler;
import org.iabako.client.tools.IabakoAsyncCallback;
import org.iabako.client.tools.Messages;
import org.iabako.client.ui.form.AbstractForm;
import org.iabako.client.ui.form.business.util.SearchActionHandler;
import org.iabako.client.ui.layout.field.*;
import org.iabako.client.ui.layout.widget.customField.CustomFieldsInstance;
import org.iabako.client.ui.layout.widget.datatable.DataTable;
import org.iabako.client.ui.layout.widget.tooltip.TooltipListener;
import org.iabako.shared.entity.business.AbstractEntity;
import org.iabako.shared.entity.business.CustomFieldValue;
import org.iabako.shared.entity.enumeration.Gender;
import org.iabako.shared.iservice.business.CustomFieldServiceAsync;
import org.iabako.shared.iservice.generic.SearchServiceAsync;
import org.iabako.shared.querydefinition.columndefinition.ClientColumnEnum;
import org.iabako.shared.querydefinition.columndefinition.ColumnDefinition;
import org.iabako.shared.querydefinition.dto.CriteriaFilterDTO;
import org.iabako.shared.querydefinition.dto.QueryDefinitionDTO;
import org.iabako.shared.querydefinition.dto.QueryOperatorEnum;
import org.iabako.shared.tools.GenericTools;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
 * TODO javadoc
 * Date: 24/11/13
 * Time: 18:22
 */
public class SearchForm extends AbstractForm {

    interface MyUiBinder extends UiBinder<HTMLPanel, SearchForm> {
    }

    protected MyUiBinder binderSearchForm = GWT.create(MyUiBinder.class);

    private final CustomFieldServiceAsync customFieldServiceAsync = CustomFieldServiceAsync.Util.getInstance();

    @UiField
    public Button actionButton;
    @UiField
    public DisclosurePanel disclosureFormPanel;
    @UiField
    public InputTextSuggest suggestInputText;
    @UiField
    public HTMLPanel disclosureFormPanelContent;
    @UiField
    public HTMLPanel clientsCategoriesPanel;
    @UiField
    public CheckboxBoolean showPerson;
    @UiField
    public CheckboxBoolean showCompany;

    public DisclosurePanel disclosurePanel;
    public com.google.gwt.user.client.ui.Button disclosureButton;

    SearchServiceAsync searchServiceAsync;
    DataTable dataTable;
    public List<CriteriaFilterDTO> criteriaList = new ArrayList<CriteriaFilterDTO>();
    CustomFieldsInstance customFieldsInstance;
    boolean searchExecuted;

    SearchActionHandler searchActionHandler = new SearchActionHandler(this);

    public void showClientCustomFieldsCriteria(final CustomFieldsInstance customFieldsInstance) {

        this.customFieldsInstance = customFieldsInstance;

        customFieldServiceAsync.getCustomCriteriaSearchFields(new IabakoAsyncCallback<List<CustomFieldValue>>() {

            public void onSuccess(List<CustomFieldValue> result) {
                super.onSuccess(result);
                customFieldsInstance.setCustomFieldValues(result);
                setHandlersToCustomFieldsInstance();
            }
        });
    }

    private void setHandlersToCustomFieldsInstance() {
        for (AbstractInputField field : customFieldsInstance.getInputValues().values()) {
            if (field instanceof AbstractInputText) {
                ((AbstractInputText) field).getInputField().addKeyUpHandler(searchActionHandler);
                ((AbstractInputText) field).getInputField().addBlurHandler(searchActionHandler);
            } else if (field instanceof InputTextDate) {
                ((InputTextDate) field).getInputFieldDate().addValueChangeHandler(searchActionHandler);
            } else if (field instanceof SelectList) {
                ((SelectList) field).getSelectField().addChangeHandler(searchActionHandler);
            }
        }
    }

    public void addToDisclosureFormPanelContent(HTMLPanel disclosureFormPanelContent) {
        this.disclosureFormPanelContent.add(disclosureFormPanelContent);
        this.disclosureFormPanel.setVisible(true);
    }

    public void setProperties(final SearchServiceAsync searchServiceAsync, DefaultSuggestHandler suggestHandler,
                              final DataTable dataTable, String principalInputStringNoValue) {

        suggestInputText.setSuggestHandler(suggestHandler);
        suggestInputText.setSelectionHandler(searchActionHandler);
        suggestInputText.getInputField().addKeyUpHandler(searchActionHandler);
        suggestInputText.getInputField().addFocusHandler(searchActionHandler);

        suggestInputText.setNoValueString(principalInputStringNoValue);

        this.dataTable = dataTable;
        this.searchServiceAsync = searchServiceAsync;
        actionButton.addClickHandler(searchActionHandler);

        disclosurePanel.addCloseHandler(new CloseHandler<DisclosurePanel>() {
            public void onClose(CloseEvent<DisclosurePanel> event) {
                cleanClientCategoriesCriteria();
                cleanSpecificCriteria();
                cleanCustomCriterias();
                if (searchExecuted) {
                    search();
                    searchExecuted = false;
                }
            }
        });

    }

    @UiFactory
    public DisclosurePanel createPanel(String label) {
        HorizontalPanel newHeader = new HorizontalPanel();
        disclosureButton = new com.google.gwt.user.client.ui.Button(Messages.getLabel("search_motor_deploy"));
        disclosureButton.setStyleName("disclosurepanelbutton searchdisclosurepanelbutton");
        newHeader.add(disclosureButton);
        disclosurePanel = new DisclosurePanel(label);
        disclosurePanel.setHeader(newHeader);

        disclosurePanel.addCloseHandler(new CloseHandler<DisclosurePanel>() {
            public void onClose(CloseEvent<DisclosurePanel> event) {
                disclosureButton.setText(Messages.getLabel("search_motor_deploy"));
            }
        });

        disclosurePanel.addOpenHandler(new OpenHandler<DisclosurePanel>() {
            public void onOpen(OpenEvent<DisclosurePanel> event) {
                disclosureButton.setText(Messages.getLabel("search_motor_undeploy"));
            }
        });

        return disclosurePanel;
    }

    public void search() {
        search(true);
    }

    public void search(final boolean showLoader) {
        searchExecuted = true;
        dataTable.queryDefinitionDTO.clearCriterias();
        criteriaList.clear();

        Long hiddenSelection = GenericTools.isEmpty(suggestInputText.getHiddenSelectionCode().getValue()) ?
                null : Long.parseLong(suggestInputText.getHiddenSelectionCode().getValue());

        addClientCategoriesCriteria();
        addSpecificCriteria();

        dataTable.queryDefinitionDTO.getCriterias().addAll(criteriaList);

        addCustomFieldsAsCriteriaSearch();

        searchServiceAsync.setSearchCriteriaFromSuggest(dataTable.queryDefinitionDTO,
                hiddenSelection,
                suggestInputText.getValue(),
                new IabakoAsyncCallback<QueryDefinitionDTO>() {
                    public void onSuccess(QueryDefinitionDTO result) {
                        dataTable.refreshSearch(result, showLoader);
                        super.onSuccess(result);
                    }
                });
    }

    protected void addSpecificCriteria() {
        //To be override
    }

    protected void cleanSpecificCriteria() {
        //To be override
    }

    public void showClientCategoriesCriteria(HTMLPanel clientsCategoriesPanel) {
        clientsCategoriesPanel.add(this.clientsCategoriesPanel);
        this.clientsCategoriesPanel.setVisible(true);
        setClientCategoriesHandlers();
    }

    private void setClientCategoriesHandlers() {
        DOM.sinkEvents(showPerson.getCheckbox().getElement(), Event.MOUSEEVENTS);
        DOM.sinkEvents(showCompany.getCheckbox().getElement(), Event.MOUSEEVENTS);

        TooltipListener showPersonLabelListener = new TooltipListener(Messages.getLabel("client_category_person"));
        showPerson.getCheckbox().addHandler(showPersonLabelListener, MouseOverEvent.getType());
        showPerson.getCheckbox().addHandler(showPersonLabelListener, MouseOutEvent.getType());

        TooltipListener showCompanyLabelListener = new TooltipListener(Messages.getLabel("client_category_company"));
        showCompany.getCheckbox().addHandler(showCompanyLabelListener, MouseOverEvent.getType());
        showCompany.getCheckbox().addHandler(showCompanyLabelListener, MouseOutEvent.getType());

        showPerson.getCheckbox().addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                if (showPerson.getValue()) {
                    showCompany.setValue(false);
                }
            }
        });
        showCompany.getCheckbox().addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                if (showCompany.getValue()) {
                    showPerson.setValue(false);
                }
            }
        });

        showPerson.getCheckbox().addClickHandler(searchActionHandler);
        showCompany.getCheckbox().addClickHandler(searchActionHandler);
    }

    public void cleanClientCategoriesCriteria() {
        showPerson.setValue(false);
        showCompany.setValue(false);
    }

    private void addClientCategoriesCriteria() {
        if (showPerson.getValue()) {
            addCriteria(ClientColumnEnum.gender, QueryOperatorEnum.NOT_EQUALS, Gender.company);
        }

        if (showCompany.getValue()) {
            addCriteria(ClientColumnEnum.gender, QueryOperatorEnum.EQUALS, Gender.company);
        }
    }

    private void addCustomFieldsAsCriteriaSearch() {

        if (customFieldsInstance == null) {
            //this form doesn't use customFields
            return;
        }
        customFieldsInstance.setInputValuesToCustomFieldValues();
        dataTable.queryDefinitionDTO.getClientCustomFieldCriterias().clear();

        for (CustomFieldValue customFieldValue : customFieldsInstance.getInputValues().keySet()) {
            AbstractInputField field = customFieldsInstance.getInputValues().get(customFieldValue);
            if (GenericTools.isEmpty(field.getValue())) {
                continue;
            }
            dataTable.queryDefinitionDTO.addClientCustomFieldCriterias(customFieldValue);
        }
    }

    public void cleanCustomCriterias() {
        customFieldsInstance.cleanInputValues();
    }

    public void addCriteria(ColumnDefinition hqlDefinition, QueryOperatorEnum queryOperatorEnum, Serializable value) {
        CriteriaFilterDTO criteriaFilterDTO = new CriteriaFilterDTO(hqlDefinition, value, queryOperatorEnum);
        criteriaList.add(criteriaFilterDTO);
    }

    @Override
    protected List<IField> getMandatoryFields() {
        return null;
    }

    @Override
    protected AbstractEntity getEntity() {
        return null;
    }

    @Override
    public boolean validate() {
        return false;
    }
}
